/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstring>
#include <string>
#include "sle_host_service.h"
#include "sle_host_hal.h"
#include "sle_loader_hal.h"
#include "sle_hilog.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {

class SleHostService::SleHostServiceCallback {
public:
    SleHostServiceCallback() = default;
    ~SleHostServiceCallback() = default;

    static void OnSleEnableResult(SleHalErrorCode errCode);
    static void OnSleDisableResult(SleHalErrorCode errCode);
    static SleHostHalCallbacks *BuildHalHostCallback();

private:
    static SleHostHalCallbacks halCallback_;
};

void SleHostService::SleHostServiceCallback::OnSleEnableResult(SleHalErrorCode errCode)
{
    auto hostService = SleHostService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(hostService, "host service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(hostService->callback_, "host service callback null error!");
    hostService->callback_->OnSleEnableResult((SleErrorCode)errCode);
}

void SleHostService::SleHostServiceCallback::OnSleDisableResult(SleHalErrorCode errCode)
{
    auto hostService = SleHostService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(hostService, "host service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(hostService->callback_, "host service callback null error!");
    hostService->callback_->OnSleDisableResult((SleErrorCode)errCode);
}

SleHostHalCallbacks SleHostService::SleHostServiceCallback::halCallback_;
SleHostHalCallbacks *SleHostService::SleHostServiceCallback::BuildHalHostCallback()
{
    SLE_LOGD("BuildHalHostCallback In");
    halCallback_.OnHostHalEnableSleCb = OnSleEnableResult;
    halCallback_.OnHosthalDisableSleCb = OnSleDisableResult;
    return &halCallback_;
}

// SleHostService
SleHostService::SleHostService()
{
    SLE_LOGD("SleHostService In");
    SleHalErrorCode ret = InitSleHal();
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "init sle hal failed(%{public}d)!", ret);
    ret = InitSleHostHal();
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "init sle host hal failed(%{public}d)!", ret);
    serviceCallback_ = std::make_unique<SleHostServiceCallback>();
    SLE_ASSERT_AND_RETURN_LOG(serviceCallback_, "create service callback ptr failed!");
    ret = SleHostHalRegisterCallback(serviceCallback_->BuildHalHostCallback());
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "register hal host callback failed(%{public}d)!", ret);
}

SleHostService::~SleHostService()
{
    SLE_LOGD("~SleHostService In");
    SleHalErrorCode ret = DeinitSleHostHal();
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "deinit sle host hal failed(%{public}d)!", ret);
    ret = DeinitSleHal();
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "deinit sle hal failed(%{public}d)!", ret);
    serviceCallback_ = nullptr;
}

SleHostService *SleHostService::GetInstance()
{
    static SleHostService instance;
    return &instance;
}

SleErrorCode SleHostService::EnableSle()
{
    SLE_LOGD("EnableSle In");
    SleHalErrorCode ret = SleHostHalEnableSle();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, (SleErrorCode)ret, "enable sle failed(%{public}d)!", ret);
    return SLE_NO_ERROR;
}

SleErrorCode SleHostService::DisableSle()
{
    SLE_LOGD("DisableSle In");
    SleHalErrorCode ret = SleHostHalDisableSle();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, (SleErrorCode)ret, "disable sle failed(%{public}d)!", ret);
    return SLE_NO_ERROR;
}

SleErrorCode SleHostService::GetHostAddress(SleAddress &address)
{
    SLE_LOGD("GetHostAddress In");
    SleDeviceAddress localAddr;
    SleHalErrorCode ret = SleHostHalGetHostAddress(&localAddr);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, (SleErrorCode)ret, "get local address failed(%{public}d)!", ret);
    SleAddress addr(localAddr);
    address = addr;
    return SLE_NO_ERROR;
}

SleErrorCode SleHostService::SetHostName(const std::string &name)
{
    SLE_LOGD("SetHostName In, set name %{public}s", name.c_str());
    SLE_ASSERT_AND_RETURN_RET_LOG(name.length() != 0, SLE_ERR_INVALID_PARAM, "name null error!");
    SleHalErrorCode ret = SleHostHalSetHostName(
        reinterpret_cast<const uint8_t *>(name.data()), static_cast<uint8_t>(name.length()));
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, (SleErrorCode)ret, "set local name failed(%{public}d)!", ret);
    return SLE_NO_ERROR;
}

SleErrorCode SleHostService::GetHostName(std::string &name)
{
    SLE_LOGD("GetHostName In");
    uint8_t localName[SLE_DEVICE_NAME_LEN];
    uint8_t length = SLE_DEVICE_NAME_LEN;
    SleHalErrorCode ret = SleHostHalGetHostName(localName, &length);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, (SleErrorCode)ret, "get local name failed(%{public}d)!", ret);
    name.assign(reinterpret_cast<char*>(localName), length);
    return SLE_NO_ERROR;
}

SleErrorCode SleHostService::RegisterHostCallback(IAdapterCallback &callback)
{
    SLE_LOGD("RegisterHostCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(
        callback_ != &callback, SLE_NO_ERROR, "callback(%p) already registered error!", &callback);
    callback_ = &callback;
    return SLE_NO_ERROR;
}

SleErrorCode SleHostService::UnregisterHostCallback(IAdapterCallback &callback)
{
    SLE_LOGD("UnregisterHostCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(
        callback_ == &callback, SLE_NO_ERROR, "callback(%p) already unregistered error!", &callback);
    callback_ = nullptr;
    return SLE_NO_ERROR;
}
} // SleStandard
} // NearLink
} // OHOS